package com.quanquan.store.service;


import DTO.user.UserDTO;
import DTO.user.UserInfoDTO;
import com.quanquan.store.configBean.RabbitSender;
import com.quanquan.store.dto.IdDTO;
import com.quanquan.store.entity.*;
import com.quanquan.store.repository.GroupBuyingRepository;
import com.quanquan.store.repository.GroupBuyingTradingRecordRepository;
import com.quanquan.store.repository.ShoppingKillAbnormalRepository;
import com.quanquan.store.request.CouponRequest;
import commond.IntegralOutPut;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import utils.DateUtils;
import utils.StringUtil;
import utils.UUIDGenerator;

import javax.persistence.criteria.Predicate;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class GroupBuyingTradingRecordService {


    private final RestTemplate restTemplate;

    public static final String INTEGRAL = "integral";
    public static final String MONEY = "money";
    private static final String GROUP_NUM = "groupNum_";

    public static final String STRING = "_";
    public static final String INVENNTORY = "invenntory";


    @Autowired
    private RabbitSender rabbitSender;

    @Autowired
    private WxPayService wxPayService;
    private final StringRedisTemplate stringRedisTemplate;

    private final ShoppingKillAbnormalRepository shoppingKillAbnormalRepository;

    private final GroupBuyingTradingRecordRepository groupBuyingTradingRecordRepository;


    private final CouponService couponService;

    private final GroupBuyingRepository groupBuyingRepository;

    public GroupBuyingTradingRecordService(RestTemplate restTemplate, StringRedisTemplate stringRedisTemplate, CouponService couponService, GroupBuyingRepository groupBuyingRepository, ShoppingKillAbnormalRepository shoppingKillAbnormalRepository, GroupBuyingTradingRecordRepository groupBuyingTradingRecordRepository) {
        this.restTemplate = restTemplate;
        this.stringRedisTemplate = stringRedisTemplate;
        this.groupBuyingTradingRecordRepository = groupBuyingTradingRecordRepository;
        this.couponService = couponService;
        this.groupBuyingRepository = groupBuyingRepository;
        this.shoppingKillAbnormalRepository = shoppingKillAbnormalRepository;
    }

    /**
     * 根据秒杀商品id查询记录
     *
     * @param groupBuyingId
     * @return
     */
    public Integer findAllByGroupBuyingId(String groupBuyingId) {
        List<GroupBuyingTradingRecord> groupBuyingTradingRecords = groupBuyingTradingRecordRepository.findByGroupBuyingId(groupBuyingId);
        //将库存量缓存回去 TODO
        return groupBuyingTradingRecords.size();
    }

    public Boolean checkTimes(String userId, String groupBuyingId) {
        Integer allCount = groupBuyingTradingRecordRepository.findAllCount(userId, groupBuyingId);
        return allCount == 0;
    }


    public boolean createRecord(String userId, String groupBuyingId, String uuid) {

        //根据秒杀商品id查询秒杀信息和价格
        GroupBuying groupBuying = groupBuyingRepository.findByIdAndRemove(groupBuyingId, 0);
        if (groupBuying != null) {
            //拿到商品id查询根据秒杀商品类型找到商品
            String goodsType = groupBuying.getGoodsType();
            String couponId = groupBuying.getGoodsId();
            GroupBuyingTradingRecord groupBuyingTradingRecord = new GroupBuyingTradingRecord();
            groupBuyingTradingRecord.setId(uuid);
            groupBuyingTradingRecord.setGoodId(couponId);
            groupBuyingTradingRecord.setGoodsType(goodsType);
            groupBuyingTradingRecord.setUserId(userId);
            groupBuyingTradingRecord.setOrderNumber(uuid);
            groupBuyingTradingRecord.setCreateTime(DateUtils.currentDate());
            String payType = groupBuying.getPayType();
            /**
             * 支付类型  integral 积分  money 现金
             */
            if (INTEGRAL.equals(payType)) {
                groupBuyingTradingRecord.setIntegral(groupBuying.getIntegral());
                groupBuyingTradingRecord.setPrice(0.0);
                groupBuyingTradingRecord.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.paid);


            }
            if (MONEY.equals(payType)) {
                groupBuyingTradingRecord.setIntegral(0);
                groupBuyingTradingRecord.setPrice(groupBuying.getPrice());
                groupBuyingTradingRecord.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.unpaid);

            }
            groupBuyingTradingRecord.setPrice(groupBuying.getPrice());
            groupBuyingTradingRecord.setGroupBuyingId(groupBuyingId);

            groupBuyingTradingRecordRepository.saveAndFlush(groupBuyingTradingRecord);

            if (INTEGRAL.equals(payType)) {
                //判断是否满员
                checkSuccess(groupBuyingId);

            }
            return true;
        }


        return false;


    }


    /**
     * 根据订单号查找订单
     *
     * @param orderNum
     * @return
     */
    public GroupBuyingTradingRecord findByOrderRecord(String orderNum) {
        return groupBuyingTradingRecordRepository.findById(orderNum).orElse(null);
    }


    public boolean updateRecord(String outTradeNo, String transactionId, GroupBuyingTradingRecord order) {
        if (order == null) {
            ShoppingKillAbnormal shoppingKillAbnormal = new ShoppingKillAbnormal();
            shoppingKillAbnormal.setId(UUIDGenerator.getUUID());
            shoppingKillAbnormal.setOutTradeNo(outTradeNo);
            shoppingKillAbnormal.setCreateTime(DateUtils.currentDate());
            shoppingKillAbnormal.setRemark("团购");
            shoppingKillAbnormalRepository.save(shoppingKillAbnormal);
            return false;
        }
        // 1.修改订单支付状态（状态，支付时间，微信支付订单号）
        String s = order.getTradingStatus().toString();
        if (s.equals("unpaid")) {
            order.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.paid);
            order.setPayTime(DateUtils.currentDate());
            order.setTransactionId(transactionId);
            groupBuyingTradingRecordRepository.saveAndFlush(order);
            stringRedisTemplate.delete(GROUP_NUM + order.getGroupBuyingId() + STRING + order.getUserId());
            //判断团购人数是否已满
            String groupBuyingId = order.getGroupBuyingId();
            checkSuccess(groupBuyingId);
            //todo
            return true;
        }

        //修改真实的库存 TODO
        return false;
    }


    public void checkSuccess(String groupBuyingId) {
        //根据团购id查询团购详情
        GroupBuying groupBuying = groupBuyingRepository.findByIdAndRemove(groupBuyingId, 0);
        Integer groupNum = groupBuying.getGroupNum();
        String couponId = groupBuying.getGoodsId();
        String killStatus = groupBuying.getKillStatus();
        Integer threshold = groupBuying.getThreshold();
        String payType = groupBuying.getPayType();

        List<GroupBuyingTradingRecord> groupBuyingList = groupBuyingTradingRecordRepository.findByGroupBuyingId(groupBuyingId);
        List<String> userIds = groupBuyingList.parallelStream().map(GroupBuyingTradingRecord::getUserId).collect(Collectors.toList());
        int size = groupBuyingList.size();
        System.out.println("size"+size);
        if (("sellOut".equals(killStatus) || "over".equals(killStatus)) && size >= threshold) {
            sendCoupon(couponId, userIds, groupBuyingId);
        }
        if ("over".equals(killStatus) && size < threshold) {
            //退款处理
            if (payType.equals("money")) {
                //将订单设置为退款中
                for(GroupBuyingTradingRecord groupBuyingTradingRecord : groupBuyingList){
                    groupBuyingTradingRecord.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.refunding);
                    groupBuyingTradingRecordRepository.save(groupBuyingTradingRecord);
                }
                //微信退款
                List<String> orderNumbers = groupBuyingList.parallelStream().map(GroupBuyingTradingRecord::getOrderNumber).collect(Collectors.toList());
                for (String orderNumber : orderNumbers) {
                    try {
                        wxPayService.refundOrder(orderNumber);
                    } catch (Exception e) {
                        System.out.println(e.getLocalizedMessage());
                    }

                }
            }
            if (payType.equals("integral")) {
                System.out.println("我已经到这里了。。。。。。。。退积分");
                //退还用户积分
                refundIntegral(groupBuyingList,groupBuying);


                //修改订单状态
            }
            groupBuying.setKillStatus("failure");

            groupBuyingRepository.save(groupBuying);


        }
        if (groupNum == size) {
            sendCoupon(couponId, userIds, groupBuyingId);
            groupBuying.setKillStatus("sellOut");
            groupBuyingRepository.save(groupBuying);
        }

    }


    /**
     * 订单处理
     */
    private void refundIntegral(List<GroupBuyingTradingRecord> groupBuyingList, GroupBuying groupBuying) {
        IntegralOutPut integralOutPut = new IntegralOutPut();
        List<String> userIds = groupBuyingList.parallelStream().map(GroupBuyingTradingRecord::getUserId).collect(Collectors.toList());

        for(String userId : userIds){
            integralOutPut.setConsumeType("group");
            integralOutPut.setForeignKeyId(groupBuying.getId());
            integralOutPut.setIntegralPoint(groupBuying.getIntegral().toString());

            integralOutPut.setOrderNum(groupBuying.getId());
            integralOutPut.setMoney("0");
            integralOutPut.setUserId(userId);
            integralOutPut.setSource("团购失败退还积分");
            integralOutPut.setTradeAction(0);
            integralOutPut.setTradingContent("团购失败退还积分：" + groupBuying.getGroupBuyingName());

            // 将计算结果放到MQ队列去补充明细的余额

            String exchange = "integral.exchange";
            String routingKey = "integral.store";
            rabbitSender.sendMessageToMQ(integralOutPut, null, exchange, routingKey);


        }

        for(GroupBuyingTradingRecord groupBuyingTradingRecord : groupBuyingList){
            groupBuyingTradingRecord.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.refund);
            groupBuyingTradingRecordRepository.save(groupBuyingTradingRecord);
        }

    }


    private void sendCoupon(String couponId, List<String> userIds, String groupBuyingId) {
        //发券
        CouponRequest couponRequest = new CouponRequest();
        couponRequest.setId(couponId);
        couponRequest.setUserIdList(userIds);
        couponRequest.setSendRequestType(1);
        //获取券的方式 1-后台手动推券 2-积分商城购买 3-秒杀 4-注册规则送券 5-邀请注册送券 6-消费满积分送券 7-团购
        Integer getType = 7;
        couponRequest.setGetType(getType);
        couponService.sendShoppingKillCoupon(couponRequest);
        //修改团购状态(通过队列修改团购记录状态)
        //发送消息推送
        Map<String, Object> properties = new HashMap<>();
        properties.put("groupBuyingId", groupBuyingId);
        //将计算结果放到MQ队列去补充明细的余额
        String msg = "修改团购记录状态";
        String exchange = "groupBuying.exchange";
        String routingKey = "updateRecord.message";
        rabbitSender.sendMessageToMQ(msg, properties, exchange, routingKey);
    }

    public List<UserDTO> findHeadImg(Integer page, Integer size, String groupBuyingId) {
        List<GroupBuyingTradingRecord> groupBuyingList = groupBuyingTradingRecordRepository.findByGroupBuyingId(groupBuyingId);
        List<String> userIds = groupBuyingList.parallelStream().map(GroupBuyingTradingRecord::getUserId).collect(Collectors.toList());
        IdDTO idDTO = new IdDTO();
        idDTO.setForeignKeyIds(userIds);

        UserInfoDTO userInfoDTO = restTemplate.postForObject("http://QUANQUAN-USER/user/query_by_id_list", idDTO, UserInfoDTO.class);
        List<UserDTO> userDTOS = userInfoDTO.getUserDTOS();
        for (UserDTO userDTO : userDTOS) {

            String memberName = userDTO.getMemberName();
            //将名字加密
            String s = filterEmoji(memberName, "");
            if (StringUtil.isEmpty(s)) {
                s = "***";
            } else {
                int length = s.length();
                if (length <= 2) {
                    s = s + "***";
                }
                if (length > 2) {
                    String first = s.substring(0, 1);
                    String last = s.substring(length - 1, length);
                    s = first + "***" + last;
                }
            }


        }
        return userDTOS;
    }

    /**
     * emoji表情替换
     *
     * @param source  原字符串
     * @param slipStr emoji表情替换成的字符串
     * @return 过滤后的字符串
     */
    public static String filterEmoji(String source, String slipStr) {
        if (StringUtils.isNotBlank(source)) {
            return source.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", slipStr);
        } else {
            return source;
        }
    }

    public void findRecord(String userId, Integer page, Integer size) {

    }

    public List<GroupBuying> queryAllRecord(String userId, Integer page, Integer size) {

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(page, size, sort);
        Page<GroupBuyingTradingRecord> paged = groupBuyingTradingRecordRepository.findAll((Specification<GroupBuyingTradingRecord>) (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(cb.equal(root.get("userId").as(String.class), userId));

            predicates.add(cb.notEqual(root.get("tradingStatus").as(GroupBuyingTradingRecord.TradingStatus.class), GroupBuyingTradingRecord.TradingStatus.overdue));


            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        }, pageable);
        List<GroupBuyingTradingRecord> content = paged.getContent();
        List<String> groupBuyingIds = content.parallelStream().map(GroupBuyingTradingRecord::getGroupBuyingId).collect(Collectors.toList());
        List<GroupBuying> groupBuyings = new ArrayList<>();
        for (String groupBuyingId : groupBuyingIds) {
            GroupBuying groupBuying = groupBuyingRepository.findByIdAndRemove(groupBuyingId, 0);
            groupBuyings.add(groupBuying);
        }
        return groupBuyings;
    }

    public void timingProcessing() {

        rollbackInventory();
        //查询所有团购查看是否过期
        List<GroupBuying> paged = groupBuyingRepository.findAll((Specification<GroupBuying>) (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            predicates.add(cb.equal(root.get("remove").as(Integer.class), 0));
            predicates.add(cb.equal(root.get("show").as(Integer.class), 0));
            predicates.add(cb.equal(root.get("killStatus").as(String.class), "processing"));


            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        });

        List<GroupBuying> list = new ArrayList<>();
        for (GroupBuying groupBuying : paged) {
            Date endTime = DateUtils.parseStr2Date("yyyy-MM-dd HH:mm", groupBuying.getEndTime());
            Date nowTime = new Date();

            if (nowTime.after(endTime)) {
                groupBuying.setKillStatus("over");
                groupBuyingRepository.save(groupBuying);
                list.add(groupBuying);
            }
        }
        //过期是否满足所有成团数
        for (GroupBuying groupBuying : list) {
            checkSuccess(groupBuying.getId());
        }
        //完成最小成团数发券


    }

    //支付超时退还库存
    private void rollbackInventory() {
        List<GroupBuyingTradingRecord> allUnpaid = groupBuyingTradingRecordRepository.findAllUnpaid();
        if (allUnpaid.size() > 0) {
            for (GroupBuyingTradingRecord groupBuyingTradingRecord : allUnpaid) {
                String createTime = groupBuyingTradingRecord.getCreateTime();
                //判断是有在3分钟以内
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime createDate = LocalDateTime.parse(createTime, df);
                LocalDateTime now = LocalDateTime.now();
                Duration between = Duration.between(createDate, now);
                long differenceTime = between.toMillis();
                if (differenceTime >= 240000L) {
                    groupBuyingTradingRecord.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.overdue);
                    groupBuyingTradingRecordRepository.saveAndFlush(groupBuyingTradingRecord);
                    incr(groupBuyingTradingRecord.getGroupBuyingId());
                }
            }
        }
    }

    //访问自增计数
    public synchronized Long incr(String key) {
        Long increment = stringRedisTemplate.opsForValue().increment(INVENNTORY + key, 1);

        return increment;
    }

    public void updateRecordStatus(String groupBuyingId) {
        List<GroupBuyingTradingRecord> groupBuyingList = groupBuyingTradingRecordRepository.findByGroupBuyingId(groupBuyingId);
        groupBuyingList.parallelStream().forEach(f -> f.setTradingStatus(GroupBuyingTradingRecord.TradingStatus.success));
        groupBuyingTradingRecordRepository.saveAll(groupBuyingList);
    }
}
